package cbr

import (
	"fmt"
	"log"
	"time"
)

// EbbFlowCBRIntegration integrates CBR protocol with EbbFlow
type EbbFlowCBRIntegration struct {
	cbrProtocol *CBRProtocol
	config      EbbFlowCBRConfig
	logger      *log.Logger
	
	// EbbFlow integration state
	currentEpoch int
	membership   []string
	threshold    int
}

// EbbFlowCBRConfig represents configuration for EbbFlow CBR integration
type EbbFlowCBRConfig struct {
	// EbbFlow parameters
	NodeID     int
	TotalNodes int
	FaultyNodes int
	
	// CBR parameters
	ReconfigurationInterval int // Execute CBR every R epochs
	NetworkConfig          NetworkConfig
	
	// Performance monitoring
	EnableMetrics bool
	MetricsPath   string
}

// NetworkConfig represents network configuration for CBR
type NetworkConfig struct {
	BaseIP    string
	BasePort  int
	IPList    []string
	PortList  []string
}

// NewEbbFlowCBRIntegration creates a new EbbFlow CBR integration
func NewEbbFlowCBRIntegration(config EbbFlowCBRConfig, logger *log.Logger) *EbbFlowCBRIntegration {
	if logger == nil {
		logger = log.Default()
	}
	
	// Create CBR protocol configuration
	cbrConfig := CBRConfig{
		OldN:       config.TotalNodes,
		OldF:       config.FaultyNodes,
		NewN:       config.TotalNodes, // Initially same as old
		NewF:       config.FaultyNodes,
		OldIPList:  config.NetworkConfig.IPList,
		OldPortList: config.NetworkConfig.PortList,
		NewIPList:  config.NetworkConfig.IPList,
		NewPortList: config.NetworkConfig.PortList,
		Timeout:    30 * time.Second,
		Retries:    3,
	}
	
	// Create CBR protocol
	cbrProtocol := NewCBRProtocol(cbrConfig, logger)
	
	return &EbbFlowCBRIntegration{
		cbrProtocol:  cbrProtocol,
		config:       config,
		logger:       logger,
		currentEpoch: 0,
		membership:   config.NetworkConfig.IPList,
		threshold:    config.FaultyNodes + 1,
	}
}

// ShouldExecuteCBR determines if CBR should be executed in current epoch
func (integration *EbbFlowCBRIntegration) ShouldExecuteCBR(epoch int) bool {
	if integration.config.ReconfigurationInterval <= 0 {
		return false
	}
	
	return epoch%integration.config.ReconfigurationInterval == 0
}

// ExecuteReconfiguration executes CBR reconfiguration for the given epoch
func (integration *EbbFlowCBRIntegration) ExecuteReconfiguration(epoch int, newMembership []string) (*CBRResult, error) {
	integration.logger.Printf("[EbbFlow-CBR] Executing reconfiguration for epoch %d", epoch)
	
	// Update CBR configuration for new membership
	if err := integration.updateCBRConfig(newMembership); err != nil {
		return nil, fmt.Errorf("failed to update CBR config: %v", err)
	}
	
	// Execute CBR protocol
	result, err := integration.cbrProtocol.ExecuteCBR()
	if err != nil {
		integration.logger.Printf("[EbbFlow-CBR] Reconfiguration failed: %v", err)
		return nil, err
	}
	
	// Update integration state
	integration.currentEpoch = epoch
	integration.membership = newMembership
	integration.threshold = integration.config.FaultyNodes + 1
	
	integration.logger.Printf("[EbbFlow-CBR] Reconfiguration completed successfully")
	return result, nil
}

// updateCBRConfig updates CBR configuration for new membership
func (integration *EbbFlowCBRIntegration) updateCBRConfig(newMembership []string) error {
	// Update network configuration
	integration.cbrProtocol.config.NewIPList = newMembership
	integration.cbrProtocol.config.NewPortList = make([]string, len(newMembership))
	
	// Generate port list based on base port
	for i, _ := range newMembership {
		integration.cbrProtocol.config.NewPortList[i] = fmt.Sprintf("%d", integration.config.NetworkConfig.BasePort+i)
	}
	
	// Update committee size
	integration.cbrProtocol.config.NewN = len(newMembership)
	
	integration.logger.Printf("[EbbFlow-CBR] Updated CBR config for %d new members", len(newMembership))
	return nil
}

// GetCurrentMembership returns the current membership
func (integration *EbbFlowCBRIntegration) GetCurrentMembership() []string {
	return integration.membership
}

// GetCurrentThreshold returns the current threshold
func (integration *EbbFlowCBRIntegration) GetCurrentThreshold() int {
	return integration.threshold
}

// GetCurrentEpoch returns the current epoch
func (integration *EbbFlowCBRIntegration) GetCurrentEpoch() int {
	return integration.currentEpoch
}

// HandleMembershipChange handles dynamic membership changes
func (integration *EbbFlowCBRIntegration) HandleMembershipChange(epoch int, joinRequests, leaveRequests []string) error {
	integration.logger.Printf("[EbbFlow-CBR] Handling membership change for epoch %d", epoch)
	
	// Calculate new membership
	newMembership := integration.calculateNewMembership(joinRequests, leaveRequests)
	
	// Check if reconfiguration is needed
	if len(joinRequests) > 0 || len(leaveRequests) > 0 {
		integration.logger.Printf("[EbbFlow-CBR] Membership change detected: +%d, -%d", len(joinRequests), len(leaveRequests))
		
		// Execute reconfiguration if needed
		if integration.ShouldExecuteCBR(epoch) {
			_, err := integration.ExecuteReconfiguration(epoch, newMembership)
			if err != nil {
				return fmt.Errorf("reconfiguration failed: %v", err)
			}
		}
	}
	
	return nil
}

// calculateNewMembership calculates new membership based on join/leave requests
func (integration *EbbFlowCBRIntegration) calculateNewMembership(joinRequests, leaveRequests []string) []string {
	// Start with current membership
	newMembership := make([]string, len(integration.membership))
	copy(newMembership, integration.membership)
	
	// Remove leaving members
	for _, leaveMember := range leaveRequests {
		for i, member := range newMembership {
			if member == leaveMember {
				newMembership = append(newMembership[:i], newMembership[i+1:]...)
				break
			}
		}
	}
	
	// Add joining members
	newMembership = append(newMembership, joinRequests...)
	
	return newMembership
}

// GetCBRMetrics returns CBR performance metrics
func (integration *EbbFlowCBRIntegration) GetCBRMetrics() *CBRMetrics {
	return &CBRMetrics{
		CurrentEpoch:    integration.currentEpoch,
		MembershipSize:  len(integration.membership),
		Threshold:       integration.threshold,
		LastReconfig:    time.Now(), // Placeholder
		ReconfigCount:   0,          // Placeholder
	}
}

// CBRMetrics represents CBR performance metrics
type CBRMetrics struct {
	CurrentEpoch   int
	MembershipSize int
	Threshold      int
	LastReconfig   time.Time
	ReconfigCount  int
}
